#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <CUnit/Basic.h>

#include "parser.h"
#include "logging.h"
#include "packer.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static int init_suite(void) {
    init_parser();

    return 0;
}

static int clean_suite(void) {
    return 0;
}

static void test_loglevel(void) {
    CU_ASSERT_EQUAL(LOG_ERR, parser.main_cfg.debug_level);
}

static void test_equal_flow_id(void) {
    struct flow_id f1;
    struct flow_id f2;

    inet_aton("10.10.10.10", &f1.src);
    inet_aton("10.10.10.11", &f1.dest);
    f1.sport = (u_short) 500;
    f1.dport = (u_short) 550;
    f1.flow_type = FLOW_TYPE_TCP;

    inet_aton("10.10.10.10", &f2.src);
    inet_aton("10.10.10.11", &f2.dest);
    f2.sport = (u_short) 500;
    f2.dport = (u_short) 550;
    f2.flow_type = FLOW_TYPE_TCP;

    CU_ASSERT(flow_id_equal(&f1, &f2));
    CU_ASSERT_EQUAL(flow_id_hash(&f1), flow_id_hash(&f2));
}

static void test_unequal_flow_id_src(void) {
    struct flow_id f1;
    struct flow_id f2;

    inet_aton("10.10.10.11", &f1.src);
    inet_aton("10.10.10.11", &f1.dest);
    f1.sport = (u_short) 500;
    f1.dport = (u_short) 550;

    inet_aton("10.10.10.10", &f2.src);
    inet_aton("10.10.10.11", &f2.dest);
    f2.sport = (u_short) 500;
    f2.dport = (u_short) 550;

    CU_ASSERT_FALSE(flow_id_equal(&f1, &f2));
    CU_ASSERT_NOT_EQUAL(flow_id_hash(&f1), flow_id_hash(&f2));
}

static void test_unequal_flow_id_dest(void) {
    struct flow_id f1;
    struct flow_id f2;

    inet_aton("10.10.10.10", &f1.src);
    inet_aton("10.10.10.12", &f1.dest);
    f1.sport = (u_short) 500;
    f1.dport = (u_short) 550;

    inet_aton("10.10.10.10", &f2.src);
    inet_aton("10.10.10.11", &f2.dest);
    f2.sport = (u_short) 500;
    f2.dport = (u_short) 550;

    CU_ASSERT_FALSE(flow_id_equal(&f1, &f2));
    CU_ASSERT_NOT_EQUAL(flow_id_hash(&f1), flow_id_hash(&f2));
}

static void test_unequal_flow_id_sport(void) {
    struct flow_id f1;
    struct flow_id f2;

    inet_aton("10.10.10.10", &f1.src);
    inet_aton("10.10.10.11", &f1.dest);
    f1.sport = (u_short) 501;
    f1.dport = (u_short) 550;

    inet_aton("10.10.10.10", &f2.src);
    inet_aton("10.10.10.11", &f2.dest);
    f2.sport = (u_short) 500;
    f2.dport = (u_short) 550;

    CU_ASSERT_FALSE(flow_id_equal(&f1, &f2));
    CU_ASSERT_NOT_EQUAL(flow_id_hash(&f1), flow_id_hash(&f2));
}

static void test_unequal_flow_id_dport(void) {
    struct flow_id f1;
    struct flow_id f2;

    inet_aton("10.10.10.10", &f1.src);
    inet_aton("10.10.10.11", &f1.dest);
    f1.sport = (u_short) 500;
    f1.dport = (u_short) 551;

    inet_aton("10.10.10.10", &f2.src);
    inet_aton("10.10.10.11", &f2.dest);
    f2.sport = (u_short) 500;
    f2.dport = (u_short) 550;

    CU_ASSERT_FALSE(flow_id_equal(&f1, &f2));
    CU_ASSERT_NOT_EQUAL(flow_id_hash(&f1), flow_id_hash(&f2));
}

static void test_init_hash_empty(void) {
    struct parser_info info;

    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 0);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 0);
    CU_ASSERT_EQUAL(parser.udp_flows_inmem, 0);

    populate_parser_info(&info);

    CU_ASSERT_EQUAL(info.avg_pkts_per_sec, 0);
    CU_ASSERT_EQUAL(info.ip_id_fields, 0);
    CU_ASSERT_EQUAL(info.tcp_flows, 0);
    CU_ASSERT_EQUAL(info.tcp_pkts, 0);
    CU_ASSERT_EQUAL(info.udp_flows, 0);
    CU_ASSERT_EQUAL(info.udp_pkts, 0);
    CU_ASSERT_EQUAL(info.tcp_win_fields, 0);
    CU_ASSERT_EQUAL(info.tcp_win_stride, 0);
    CU_ASSERT_EQUAL(info.ip_ttl_fields, 0);
    CU_ASSERT_EQUAL(info.ip_ttl_stride, 0);
}

static void test_get_new_flow(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    
    
    struct flow *f = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_UDP);

    CU_ASSERT_NOT_EQUAL(f, NULL);
    CU_ASSERT_EQUAL(f->info.flow_length, 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 1);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 0);
    CU_ASSERT_EQUAL(parser.udp_flows_inmem, 1);

    clear_flows();
}

// TODO: test clear flows when flow not empty - make sure counters are reset

static void test_clear_flows_empty(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_UDP);
    UNUSED(f);

    clear_flows();

    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 0);
    CU_ASSERT_EQUAL(parser.udp_flows_inmem, 0);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 0);
}

static void test_get_same_flow(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f1 = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_TCP);
    struct flow *f2 = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_TCP);

    CU_ASSERT_EQUAL(f1, f2);
    CU_ASSERT_EQUAL(f1->info.flow_length, 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 1);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 1);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 1);

    clear_flows();
}

static void test_get_different_flows(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f1 = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_TCP);
    struct flow *f2 = get_flow(src, (u_short) 510, dest, (u_short) 550,
            FLOW_TYPE_TCP);

    CU_ASSERT_NOT_EQUAL(f1, f2);
    CU_ASSERT_EQUAL(f1->info.flow_length, 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 2);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 2);
    CU_ASSERT_EQUAL(parser.udp_flows_inmem, 0);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 2);

    clear_flows();
}

static void test_get_different_flows_type(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f1 = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_TCP);
    struct flow *f2 = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_UDP);

    CU_ASSERT_NOT_EQUAL(f1, f2);
    CU_ASSERT_EQUAL(f1->info.flow_length, 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 2);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 1);
    CU_ASSERT_EQUAL(parser.udp_flows_inmem, 1);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 2);

    clear_flows();
}

static void test_get_two_same_one_different_flow(void) {
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f1 = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_TCP);
    struct flow *f2 = get_flow(src, (u_short) 500, dest,
            (u_short) 560, FLOW_TYPE_TCP);
    struct flow *f3 = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_TCP);

    CU_ASSERT_NOT_EQUAL(f1, f2);
    CU_ASSERT_NOT_EQUAL(f2, f3);
    CU_ASSERT_EQUAL(f1, f3);
    CU_ASSERT_EQUAL(f1->info.flow_length, 0);
    CU_ASSERT_EQUAL(f2->info.flow_length, 0);
    CU_ASSERT_EQUAL(parser.flow_ids_inmem, 2);
    CU_ASSERT_EQUAL(parser.tcp_flows_inmem, 2);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 2);

    clear_flows();
}

static void test_handle_pkt(void) {
    struct parser_info info;
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f = get_flow(src, (u_short) 500, dest,
            (u_short) 550, FLOW_TYPE_UDP);
    int ret = handle_udp_pkt_longarg((struct udp_flow *) f, 1, 1, 1, 1);

    populate_parser_info(&info);

    CU_ASSERT_EQUAL(ret, 0);
    CU_ASSERT_EQUAL(f->info.flow_length, 1);
    CU_ASSERT_EQUAL(info.udp_pkts, 1);
    CU_ASSERT_EQUAL(info.udp_flows, 1);
    CU_ASSERT_EQUAL(info.tcp_pkts, 0);
    CU_ASSERT_EQUAL(info.ip_id_fields, 1);
    CU_ASSERT_EQUAL(info.ip_id_stride, 0);
    CU_ASSERT_EQUAL(info.ip_len_fields, 1);
    CU_ASSERT_EQUAL(info.ip_len_stride, 0);
    CU_ASSERT_EQUAL(info.ip_ttl_fields, 1);
    CU_ASSERT_EQUAL(info.ip_ttl_stride, 0);
    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 1);

    clear_flows();
}

STRIDE_FIELD(test_stride, uint32_t, 0);

static void test_stride_init(void) {
    stride_field(test_stride) s;
    init_stride_field(test_stride, &s);
    
    size_t fields = 0, strides = 0;
    
    get_size(test_stride, &s, &fields, &strides);
    
    CU_ASSERT_EQUAL(fields, 0);
    CU_ASSERT_EQUAL(strides, 0);
}

static void test_stride_one(void) {
    stride_field(test_stride) s;
    init_stride_field(test_stride, &s);
    
    size_t fields = 0, strides = 0;
    
    add_val(test_stride, &s, 1);
    get_size(test_stride, &s, &fields, &strides);
    
    CU_ASSERT_EQUAL(fields, 1);
    CU_ASSERT_EQUAL(strides, 0);
}

static void test_stride_two(void) {
    stride_field(test_stride) s;
    init_stride_field(test_stride, &s);
    
    size_t fields = 0, strides = 0;
    
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 5);
    get_size(test_stride, &s, &fields, &strides);
    
    CU_ASSERT_EQUAL(fields, 1);
    CU_ASSERT_EQUAL(strides, 1);
}

static void test_stride_three(void) {
    stride_field(test_stride) s;
    init_stride_field(test_stride, &s);
    
    size_t fields = 0, strides = 0;
    
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    add_val(test_stride, &s, 1);
    get_size(test_stride, &s, &fields, &strides);
    
    CU_ASSERT_EQUAL(fields, 1);
    CU_ASSERT_EQUAL(strides, 6);
}

static void test_stride_four(void) {
    stride_field(test_stride) s;
    init_stride_field(test_stride, &s);
    int i;
    
    size_t fields = 0, strides = 0;
    
    add_val(test_stride, &s, 10);
    for (i = 0; i < 1000; i++) {
        add_val(test_stride, &s, 10 + 2*i);
    }
    
    get_size(test_stride, &s, &fields, &strides);
    
    CU_ASSERT_EQUAL(fields, 2);    
    CU_ASSERT_EQUAL(strides, 999);
}

static void test_handle_tcp_pkt(void) {
    struct parser_info info;
    struct in_addr src;
    struct in_addr dest;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_TCP);
    int ret = handle_tcp_pkt_longarg((struct tcp_flow *) f, 500, 10, 20,
            10, 10, 10, 10, 100);

    populate_parser_info(&info);

    CU_ASSERT_EQUAL(ret, 0);
    CU_ASSERT_EQUAL(f->info.flow_length, 1);
    CU_ASSERT_EQUAL(info.udp_pkts, 0);
    CU_ASSERT_EQUAL(info.udp_flows, 0);
    CU_ASSERT_EQUAL(info.tcp_pkts, 1);
    CU_ASSERT_EQUAL(info.tcp_flows, 1);
    CU_ASSERT_EQUAL(info.ip_id_fields, 1);
    CU_ASSERT_EQUAL(info.ip_id_stride, 0);
    CU_ASSERT_EQUAL(info.ip_len_fields, 1);
    CU_ASSERT_EQUAL(info.ip_len_stride, 0);
    CU_ASSERT_EQUAL(info.ip_ttl_fields, 1);
    CU_ASSERT_EQUAL(info.ip_ttl_stride, 0);
    CU_ASSERT_EQUAL(info.tcp_flags_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_flags_stride, 0);
    CU_ASSERT_EQUAL(info.tcp_seq_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_seq_stride, 0);
    CU_ASSERT_EQUAL(info.tcp_ack_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_ack_stride, 0);
    CU_ASSERT_EQUAL(info.tcp_flags_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_flags_stride, 0);

    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 1);

    clear_flows();
}

static void test_handle_tcp_pkts(void) {
    struct parser_info info;
    struct in_addr src;
    struct in_addr dest;
    int i;

    inet_aton("10.10.10.10", &src);
    inet_aton("10.10.10.11", &dest);

    struct flow *f = get_flow(src, (u_short) 500, dest, (u_short) 550,
            FLOW_TYPE_TCP);
    int ret = handle_tcp_pkt_longarg((struct tcp_flow *) f, htons(500), htons(10), 20,
            htonl(10), htonl(10), 10, htons(10), 100);
    
    for (i = 0; i < 1000; i++) {
        ret |= handle_tcp_pkt_longarg((struct tcp_flow *) f, 
                htons(500 + i), htons(10 + 2*i), 20, htonl(10), htonl(10), 
                10, htons(10), 100);
    }

    populate_parser_info(&info);

    CU_ASSERT_EQUAL(ret, 0);
    CU_ASSERT_EQUAL(f->info.flow_length, 1001);
    CU_ASSERT_EQUAL(info.udp_pkts, 0);
    CU_ASSERT_EQUAL(info.udp_flows, 0);
    CU_ASSERT_EQUAL(info.tcp_pkts, 1001);
    CU_ASSERT_EQUAL(info.tcp_flows, 1);    
    CU_ASSERT_EQUAL(info.ip_id_fields, 2);
    CU_ASSERT_EQUAL(info.ip_id_stride, 999);    
    CU_ASSERT_EQUAL(info.ip_len_fields, 2);
    CU_ASSERT_EQUAL(info.ip_len_stride, 999);
    CU_ASSERT_EQUAL(info.ip_ttl_fields, 1);
    CU_ASSERT_EQUAL(info.ip_ttl_stride, 1000);
    CU_ASSERT_EQUAL(info.tcp_flags_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_flags_stride, 1000);
    CU_ASSERT_EQUAL(info.tcp_seq_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_seq_stride, 1000);
    CU_ASSERT_EQUAL(info.tcp_ack_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_ack_stride, 1000);
    CU_ASSERT_EQUAL(info.tcp_win_fields, 1);
    CU_ASSERT_EQUAL(info.tcp_win_stride, 1000);

    CU_ASSERT_EQUAL(kh_size(parser.flows_table), 1);

    clear_flows();
}

static void test_packer_init(void) {
    struct uint_seq seq;

    packer_init(&seq);

    CU_ASSERT_EQUAL(seq.len, 0);
    CU_ASSERT_EQUAL(kv_size(seq.array), 0);
}

static void test_packer_append_too_big(void) {
    struct uint_seq seq;

    packer_init(&seq);
    CU_ASSERT_EQUAL(packer_append(&seq, UINT32_MAX - 10), -1);    
    CU_ASSERT_EQUAL(seq.len, 0);
    CU_ASSERT_EQUAL(kv_size(seq.array), 0);
}

static void test_packer_small(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    for (i = 0; i < 10; i++) {
        packer_append(&seq, 1);
    }
    
    CU_ASSERT_EQUAL(seq.len, 10);
    CU_ASSERT_EQUAL(kv_size(seq.array), 10);
    
    packer_init_iterator(&seq, &it);
    
    for (i = 0; i < 10; i++) {
        val = packer_iterate(&it);        
        CU_ASSERT_EQUAL(val, 1);        
    }
}

static void test_packer_med(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    for (i = 0; i < 10; i++) {
        packer_append(&seq, 250);
    }
    
    CU_ASSERT_EQUAL(seq.len, 10);
    CU_ASSERT_EQUAL(kv_size(seq.array), 20);
    
    packer_init_iterator(&seq, &it);
    
    for (i = 0; i < 10; i++) {
        val = packer_iterate(&it);        
        CU_ASSERT_EQUAL(val, 250);        
    }
}

static void test_packer_med_two(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    for (i = 0; i < 10; i++) {
        packer_append(&seq, 1250);
    }
    
    CU_ASSERT_EQUAL(seq.len, 10);
    CU_ASSERT_EQUAL(kv_size(seq.array), 20);
    
    packer_init_iterator(&seq, &it);
    
    for (i = 0; i < 10; i++) {
        val = packer_iterate(&it);        
        CU_ASSERT_EQUAL(val, 1250);        
    }
}

static void test_packer_large(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    for (i = 0; i < 10; i++) {
        packer_append(&seq, 2194304);
    }
    
    CU_ASSERT_EQUAL(seq.len, 10);
    CU_ASSERT_EQUAL(kv_size(seq.array), 30);
    
    packer_init_iterator(&seq, &it);
    
    for (i = 0; i < 10; i++) {
        val = packer_iterate(&it);         
        CU_ASSERT_EQUAL(val, 2194304);        
    }
}

static void test_packer_full(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    for (i = 0; i < 10; i++) {
        packer_append(&seq, 1073741823);
    }
    
    CU_ASSERT_EQUAL(seq.len, 10);
    CU_ASSERT_EQUAL(kv_size(seq.array), 40);
    
    packer_init_iterator(&seq, &it);
    
    for (i = 0; i < 10; i++) {
        val = packer_iterate(&it);         
        CU_ASSERT_EQUAL(val, 1073741823);        
    }
}

static void test_packer_mix(void) {
    struct uint_seq seq;
    struct packer_iterator it;
    uint32_t i, val;

    packer_init(&seq);

    packer_append(&seq, 1); // 1 byte
    packer_append(&seq, 250); // 2 bytes
    packer_append(&seq, 1250); // 2 bytes
    packer_append(&seq, 2194304); // 3 bytes
    packer_append(&seq, 1073741823); // 4 bytes
        
    CU_ASSERT_EQUAL(seq.len, 5);
    CU_ASSERT_EQUAL(kv_size(seq.array), 12);
    
    packer_init_iterator(&seq, &it);
        
    val = packer_iterate(&it);         
    CU_ASSERT_EQUAL(val, 1);        
    val = packer_iterate(&it);         
    CU_ASSERT_EQUAL(val, 250);        
    val = packer_iterate(&it);         
    CU_ASSERT_EQUAL(val, 1250);        
    val = packer_iterate(&it);         
    CU_ASSERT_EQUAL(val, 2194304);        
    val = packer_iterate(&it);         
    CU_ASSERT_EQUAL(val, 1073741823);            
}

/* The main() function for setting up and running the tests.
 * Returns a CUE_SUCCESS on successful running, another
 * CUnit error code on failure.
 */
int main() {
    CU_pSuite pSuite = NULL;

    /* initialize the CUnit test registry */
    if (CUE_SUCCESS != CU_initialize_registry())
        return CU_get_error();

    /* add a suite to the registry */
    pSuite = CU_add_suite("default_config_test", init_suite, clean_suite);
    if (NULL == pSuite) {
        CU_cleanup_registry();
        return CU_get_error();
    }

    /* add the tests to the suite */
    if ((
            NULL == CU_add_test(pSuite, "test_loglevel", test_loglevel) ||
            NULL == CU_add_test(pSuite, "test_equal_flow_id", test_equal_flow_id) ||
            NULL == CU_add_test(pSuite, "test_unequal_flow_id_src", test_unequal_flow_id_src) ||
            NULL == CU_add_test(pSuite, "test_unequal_flow_id_dest", test_unequal_flow_id_dest) ||
            NULL == CU_add_test(pSuite, "test_unequal_flow_id_sport", test_unequal_flow_id_sport) ||
            NULL == CU_add_test(pSuite, "test_unequal_flow_id_dport", test_unequal_flow_id_dport) ||
            NULL == CU_add_test(pSuite, "test_init_hash_empty", test_init_hash_empty) ||
            NULL == CU_add_test(pSuite, "test_get_new_flow", test_get_new_flow) ||
            NULL == CU_add_test(pSuite, "test_get_same_flow", test_get_same_flow) ||
            NULL == CU_add_test(pSuite, "test_get_different_flows", test_get_different_flows) ||
            NULL == CU_add_test(pSuite, "test_get_different_flows_type", test_get_different_flows_type) ||
            NULL == CU_add_test(pSuite, "test_get_two_same_one_different_flow", test_get_two_same_one_different_flow) ||
            NULL == CU_add_test(pSuite, "test_clear_flows_empty", test_clear_flows_empty) ||
            NULL == CU_add_test(pSuite, "test_handle_pkt", test_handle_pkt) ||
            NULL == CU_add_test(pSuite, "test_packer_small", test_packer_small) ||
            NULL == CU_add_test(pSuite, "test_packer_med", test_packer_med) ||
            NULL == CU_add_test(pSuite, "test_packer_med_two", test_packer_med_two) ||
            NULL == CU_add_test(pSuite, "test_packer_large", test_packer_large) ||
            NULL == CU_add_test(pSuite, "test_packer_full", test_packer_large) ||
            NULL == CU_add_test(pSuite, "test_packer_mix", test_packer_mix) ||
            NULL == CU_add_test(pSuite, "test_packer_append_too_big", test_packer_append_too_big) ||
            NULL == CU_add_test(pSuite, "test_packer_init", test_packer_init) ||
            NULL == CU_add_test(pSuite, "test_stride_init", test_stride_init) ||
            NULL == CU_add_test(pSuite, "test_stride_one", test_stride_one) ||
            NULL == CU_add_test(pSuite, "test_stride_two", test_stride_two) ||
            NULL == CU_add_test(pSuite, "test_stride_three", test_stride_three) ||
            NULL == CU_add_test(pSuite, "test_stride_four", test_stride_four) ||
            NULL == CU_add_test(pSuite, "test_handle_tcp_pkts", test_handle_tcp_pkts) ||
            NULL == CU_add_test(pSuite, "test_handle_tcp_pkt", test_handle_tcp_pkt))) {
        CU_cleanup_registry();
        return CU_get_error();
    }

    /* Run all tests using the CUnit Basic interface */
    CU_basic_set_mode(CU_BRM_VERBOSE);
    CU_basic_run_tests();
    CU_cleanup_registry();
    return CU_get_error();
}
